pacman:: p_load(sf, spatstat, tmap, rvest, tidyverse)02-2: 2nd Order Spatial Point Patterns Analysis Methods
execute: echo: true #display the code eval: true message: false warning: false freeze: false # true: not render if nothing edited editor: visual —
1 Overview
This exercise uses second-order spatial point pattern analysis and spatstat package to study childcare centres in Singapore. Unlike first-order analysis, which looks only at overall density independently, second-order methods reveal relationships and influences between centres (points) based on distance.
We aim to answer two key questions:
Are childcare centres randomly distributed across Singapore?
If not, where are the areas with higher concentrations?
2 The data
As also used in 1st order SPPA, the following datasets were downloaded from publicly available websites, and both are available in KML and GeoJSON format.
| Dataset Name | Source | Discrption |
|---|---|---|
| Child Care Services | data.gov.sg | Point feature data: contains the locations and attributes of childcare centres. |
| Master plan 2019 Subzone Boundary (No Sea) | singstat | Polygon feature data: represents the URA 2019 Master Plan planning subzone boundaries. |
3 Installing and Loading the R packages
In addition to spatstat, a total of five R packages will be used in this exercise.
| Package | Discription |
|---|---|
| sf | Simple Features, a new R package which handles importing, managing, and processing vector-based geospatial data. |
| spatstat | Provides useful functions for SPPA, which will be called to conduct both 1st and 2nd SPPA and KDE. |
| tmap | Creates high quality static or interactive choropleth maps via leaflet. |
| rvest | Scrapes and extracts data from web pages. |
After installation, we load them into R environment using the code below.
4 Data Import and Preparation
The following code chunk shows the steps to first import the Master plan 2019 Subzone Boundary (No Sea) data using st_read, extract the required 4 columns from the Description field, filter out the nearby islands, and finally save the file as mpsz_cl for further analysis.
mpsz_sf <- st_read("data/MasterPlan2019SubzoneBoundaryNoSeaKML.kml") %>%
st_zm(drop = TRUE, what = "ZM") %>%
st_transform(crs = 3414)Reading layer `URA_MP19_SUBZONE_NO_SEA_PL' from data source
`C:\lsrgc\ISSS626-yiqiong-pan\Hands-on_Ex\Hands-on_Ex02\data\MasterPlan2019SubzoneBoundaryNoSeaKML.kml'
using driver `KML'
Simple feature collection with 332 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 103.6057 ymin: 1.158699 xmax: 104.0885 ymax: 1.470775
Geodetic CRS: WGS 84
extract_kml_field <- function(html_text, field_name) {
if (is.na(html_text) || html_text == "") return(NA_character_)
page <- read_html(html_text)
rows <- page %>% html_elements("tr")
value <- rows %>%
keep(~ html_text2(html_element(.x, "th")) == field_name) %>%
html_element("td") %>%
html_text2()
if (length(value) == 0) NA_character_ else value
}# map_chr of purr (tidyverse) applies a function to each element of a list/vector and returns a character vector.
mpsz_sf <- mpsz_sf %>%
mutate(
REGION_N = map_chr(Description, extract_kml_field, "REGION_N"),
PLN_AREA_N = map_chr(Description, extract_kml_field, "PLN_AREA_N"),
SUBZONE_N = map_chr(Description, extract_kml_field, "SUBZONE_N"),
SUBZONE_C = map_chr(Description, extract_kml_field, "SUBZONE_C")
) %>%
select(-Name, -Description) %>%
relocate(geometry, .after = last_col())mpsz_cl <- mpsz_sf %>%
filter(SUBZONE_N != "SOUTHERN GROUP",
PLN_AREA_N != "WESTERN ISLANDS",
PLN_AREA_N != "NORTH-EASTERN ISLANDS")write_rds(mpsz_cl,
"data/mpsz_cl.rds")The code chuck below imports downloaded ChildCareServices data to R as sf data frame as childcare_sf by using st_read, coverts 3d to 2d (st_zm) and finally transform the CRS from WGS84 to SVY21.
childcare_sf <- st_read("data/ChildCareServices.geojson") %>%
st_zm(drop = TRUE, what = "ZM") %>% # Drop Z and M to convert from multi-dimensional to 2d (XY)
st_transform(crs = 3414)Reading layer `ChildCareServices' from data source
`C:\lsrgc\ISSS626-yiqiong-pan\Hands-on_Ex\Hands-on_Ex02\data\ChildCareServices.geojson'
using driver `GeoJSON'
Simple feature collection with 1925 features and 2 fields
Geometry type: POINT
Dimension: XYZ
Bounding box: xmin: 103.6878 ymin: 1.247759 xmax: 103.9897 ymax: 1.462134
z_range: zmin: 0 zmax: 0
Geodetic CRS: WGS 84
Using the tmap mapping methods, the code chunk below creates a map combining childcare_sf and mpsz_cl.
tm_shape(mpsz_cl)+
tm_polygons()
tm_shape(childcare_sf) +
tm_dots(size = 0.01, alpha=0.5)
── tmap v3 code detected ───────────────────────────────────────────────────────
[v3->v4] `tm_dots()`: use `fill_alpha` instead of `alpha`.

Alternatively, an interactive thematic map can be plotted using the code below. The interactive map is easy to navigate and query intuitively. It is optional to change the background map layer(choices: ESRI.WorldGrayCanvas(default), OpenStreetMap, ESRI.WorldTopoMap).
tmap_mode('view')ℹ tmap mode set to "view".
tm_shape(childcare_sf) +
tm_dots() #creates a layer of dots to visualise point data on a map.Registered S3 method overwritten by 'jsonify':
method from
print.json jsonlite
tmap_mode('plot') #switch back static mapsℹ tmap mode set to "plot".
It is advised to always switch back to plot mode to save connection consumption and limit the number of interactive maps to 10 in one documents when publishing.
5 Second-order Spatial Point Patterns Analysis
6 Analysing Spatial Point Process Using G-Function
6.1 Choa Chu Kang planning area
6.2 Tampines planning area
7 Analysing Spatial Point Process Using F-Function
7.1 Choa Chu Kang planning area
7.2 Performing Complete Spatial Randomness Test
7.3 Tampines planning area
8 Analysing Spatial Point Process Using K-Function
8.1 Choa Chu Kang planning area
8.2 Tampines planning area
9 Analysing Spatial Point Process Using L-Function
9.1 Choa Chu Kang planning area
9.2 Tampines planning area
10 Reference
Kam, T. S. 2nd Order Spatial Point Patterns Analysis Methods. R for Geospatial Data Science and Analytics. https://r4gdsa.netlify.app/chap05